package com.example.singletask.util

import io.reactivex.Maybe
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers

open class SingleTask<RESULT> {

    private var disposable: Disposable? = null
    var isCancelled: Boolean = false
        private set

    private var successAction: ((RESULT) -> Unit)? = null
    private var errorAction: ((Throwable) -> Unit)? = null
    private var beforeAction: (() -> Unit)? = null
    private var interruptedAction: (() -> Unit)? = null

    private var isSuccess: Boolean = false
    private var running = false
    private var hasError = false

    val isRunning: Boolean
        get() = disposable != null &&
                !disposable!!.isDisposed &&
                running &&
                !isCancelled

    /**
     * 启动任务
     */
    fun start(): SingleTask<RESULT> {
        if (isRunning)
            throw IllegalStateException("already started")

        val current = this
        hasError = false
        isCancelled = false
        isSuccess = false
        running = true

        // BEFORE
        current.onTaskBefore()
        beforeAction?.invoke()

        disposable = Maybe.create<RESULT> { emitter ->
            try {
                val result = onTaskRun()
                emitter.onSuccess(result)
            } catch (e: Exception) {
                if (!isCancelled)
                    emitter.onError(e)
            }
        }.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .unsubscribeOn(AndroidSchedulers.mainThread())
            .doOnDispose {

                // CANCEL
                if (!isSuccess && !hasError) {
                    Single.just(isCancelled)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe { isCancelled ->
                            if (isCancelled) {
                                onTaskInterrupted()
                                interruptedAction?.invoke()
                            }
                        }
                }
            }
            .subscribe(
                // SUCCESS
                { result ->
                    if (!isCancelled) {
                        running = false
                        isSuccess = true
                        current.onTaskSuccess(result)
                        successAction?.invoke(result)
                    }
                },
                // ERROR
                { throwable ->
                    if (!isCancelled) {
                        running = false
                        isSuccess = false
                        hasError = true
                        current.onTaskError(throwable)
                        errorAction?.invoke(throwable)
                    }
                })


        return this
    }

    /**
     * 主动中断任务
     */
    fun cancel(){
        isCancelled = true
        disposable?.dispose()
    }

    /**
     * 事件：任务执行前
     */
    fun before(action: () -> Unit): SingleTask<RESULT> {
        beforeAction = action
        return this
    }

    /**
     * 事件:任务成功
     */
    fun success(action: (RESULT) -> Unit): SingleTask<RESULT> {
        successAction = action
        return this
    }

    /**
     * 事件:任务出错
     */
    fun error(action: (Throwable) -> Unit): SingleTask<RESULT> {
        errorAction = action
        return this
    }


    /**
     * 事件：任务主动中断
     */
    fun interrupted(action: () -> Unit): SingleTask<RESULT> {
        interruptedAction = action
        return this
    }

    protected fun onTaskBefore(){}

    @Throws(Exception::class)
    protected open fun onTaskRun(): RESULT{
        throw NotImplementedError()
    }

    protected fun onTaskSuccess(result: RESULT){}

    protected fun onTaskError(error: Throwable){}

    protected fun onTaskInterrupted(){}
}